#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define N 128

typedef struct
{
    char mtype;
    char mname[N];
    char mtext[N];
} msg_t;

int main(int argc, char const *argv[])
{
    int ret, sockfd;
    struct sockaddr_in server_addr;
    char buf[N] = {0};

    socklen_t addrclen = sizeof(server_addr);

    if (argc != 3)
    {
        fprintf(stderr, "错误：运行程序时请带入参数(./06-udp_server ip port)\n");
        exit(-1);
    }

    msg_t msg;
    memset(&msg, 0, sizeof(msg));

    //用户数据包，使用udp
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("sockfd");
        exit(-1);
    }

    printf("sockdf =%d\n", sockfd);

    memset(&server_addr, 0, sizeof(server_addr));     // 清空结构体
    server_addr.sin_family = AF_INET;                 // 什么类型的通信
    server_addr.sin_port = htons(atoi(argv[2]));      // 设置socket 的固定端口
    server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 把字符串ip转换成网络二进制的ip地址

    printf("请输入你的名字>:");
    fgets(msg.mname, N, stdin);
    msg.mname[strlen(msg.mname) - 1] = 0; // 去除 '\n'
    msg.mtype = 'L';

    ret = sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret < 0)
    {
        perror("sendto");
        exit(-1);
    }

    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork");
        exit(-1);
    }

    else if (pid == 0) //子进程
    {
        while (1)
        {
            printf("请输入内容>:");
            fgets(msg.mtext, N, stdin);
            msg.mtext[strlen(msg.mtext) - 1] = 0;
            if (strncmp(msg.mtext, "quit", 4) == 0)
            {
                msg.mtype = 'Q'; // 程序退出

                ret = sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
                if (ret < 0)
                {
                    perror("sendto");
                    exit(-1);
                }

                // 客户端退出 , 退出是杀死父进程
                kill(getppid(), SIGUSR1);
                exit(0); // 子进程结束
            }

            else
            {
                msg.mtype = 'C';

                ret = sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
                if (ret < 0)
                {
                    perror("sendto");
                    exit(-1);
                }
            }
        }
    }
    else //父进程
    {
        while (1)
        {
            ret = recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL);
            if (ret < 0)
            {
                perror("recvfrom");
                exit(-1);
            }

            printf("%s:%s\n", msg.mname, msg.mtext);
        }
    }

    return 0;
}
